package org.acghub.reflection.module;

import org.acghub.common.topology.CircleFinder;
import org.acghub.common.topology.DAGTopologyGraph;
import org.reflections.Reflections;
import org.reflections.util.ConfigurationBuilder;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @Project demos
 * @Package org.acghub.reflection
 * @Desc
 * @Author Administrator
 * @Date 2025/7/16/星期三 10:15
 * @Version 1.0
 */
public class ReflectionModuleManager {

    private static volatile ReflectionModuleManager INSTANCE = new ReflectionModuleManager();

    private final Map<Class<? extends ReflectionModule>, ModuleWrapper> class2Modules = new HashMap<>();

    private final Map<String, ModuleWrapper> name2Modules = new HashMap<>();

    private final List<ModuleWrapper> sortedModules = new ArrayList<>();

    private ReflectionModuleManager() {

    }

    public static ReflectionModuleManager getInstance() {
        return INSTANCE;
    }

    /**
     * 初始化所有模块
     *
     * @param modulePackages
     */
    public void init(Collection<String> modulePackages) {
        //1.注册
        Reflections moduleReflections = new Reflections(new ConfigurationBuilder().forPackages(modulePackages.toArray(new String[0])));
        Set<Class<? extends AbstractReflectionModule>> moduleClasses = moduleReflections.getSubTypesOf(AbstractReflectionModule.class);
        for (Class<? extends AbstractReflectionModule> moduleClass : moduleClasses) {
            registerModule(moduleClass);
        }

        // 2.检查依赖，生成拓扑排序
        checkAndTopology();

        // 3.初始化
        for (ModuleWrapper moduleWrapper : sortedModules) {
            moduleWrapper.setReflections(moduleWrapper.getPackages());
            moduleWrapper.init();
        }
    }

    public ReflectionModuleManager reload(Collection<String> modulePackages) {
        ReflectionModuleManager newManager = new ReflectionModuleManager();
        newManager.init(modulePackages);
        ReflectionModuleManager oldManager = INSTANCE;
        INSTANCE = newManager;
        return oldManager;
    }

    public void reloadModule(String moduleName) {
        reloadModule0(moduleName, null, true);
    }

    public void reloadModule(String moduleName, Collection<String> reloadModulePackages) {
        reloadModule0(moduleName, reloadModulePackages, false);
    }

    public void reloadModule(Class<? extends AbstractReflectionModule> moduleClass) {
        reloadModule0(moduleClass, null, true);
    }

    public void reloadModule(Class<? extends AbstractReflectionModule> moduleClass, Collection<String> reloadModulePackages) {
        reloadModule0(moduleClass, reloadModulePackages, false);
    }

    public void exit() {
        List<ModuleWrapper> moduleWrapperCopies = new ArrayList<>(sortedModules);
        Collections.reverse(moduleWrapperCopies);
        for (ModuleWrapper moduleWrapper : moduleWrapperCopies) {
            moduleWrapper.exit();
        }
    }

    private void checkAndTopology() {
        // 1.创建有向无环拓扑排序图
        final DAGTopologyGraph<ModuleWrapper> topologyGraph = new DAGTopologyGraph<>();

        for (ModuleWrapper moduleWrapper : class2Modules.values()) {
            // 1.添加孤立节点
            topologyGraph.addIsolatedNode(moduleWrapper);
            for (Class<? extends ReflectionModule> dependencyClazz : moduleWrapper.getDependencies()) {

                final ModuleWrapper dependecyModuleWrapper = class2Modules.get(dependencyClazz);
                Objects.requireNonNull(dependencyClazz, "模块" + moduleWrapper.getName() + "依赖的模块" + dependencyClazz.getName() + "不存在");

                if (moduleWrapper.delegate().getClass().equals(dependencyClazz)) {
                    throw new RuntimeException("模块" + moduleWrapper.getName() + "依赖的模块" + dependencyClazz.getName() + "不能依赖自己");
                }
                // 1.1.加边时,会把孤立节点删掉
                topologyGraph.addEdge(dependecyModuleWrapper, moduleWrapper);
            }
        }

        // 2.检测环
        CircleFinder.FindCircleResp<ModuleWrapper> resp = topologyGraph.findCircle();
        resp.throwIfCircle(moduleWrapper -> moduleWrapper.delegate().getClass().getSimpleName());

        // 3.生成拓扑排序队列
        final List<ModuleWrapper> topologyQueue = topologyGraph.topologyQueue(Comparator.comparingInt(ModuleWrapper::getPriority));
        sortedModules.clear();
        sortedModules.addAll(topologyQueue);
    }


    private void registerModule(Class<? extends AbstractReflectionModule> clazz) {
        if (Modifier.isAbstract(clazz.getModifiers())) {
            return;
        }

        if (!clazz.isAnnotationPresent(ReflectionModuleAnno.class)) {
            throw new NullPointerException("Class " + clazz.getName() + " is not a ReflectionModule");
        }

        ModuleWrapper moduleWrapper = createModuleWrapper(clazz);

        if (class2Modules.containsKey(clazz)) {
            throw new IllegalArgumentException("Class " + clazz.getName() + " already exists");
        }
        if (name2Modules.containsKey(moduleWrapper.getName())) {
            throw new IllegalArgumentException("Module " + moduleWrapper.getName() + " already exists");
        }
        class2Modules.put(clazz, moduleWrapper);
        name2Modules.put(moduleWrapper.getName(), moduleWrapper);
    }

    private ModuleWrapper createModuleWrapper(Class<? extends AbstractReflectionModule> clazz) {
        ReflectionModuleAnno anno = clazz.getAnnotation(ReflectionModuleAnno.class);
        if (anno == null) {
            throw new NullPointerException("Class " + clazz.getName() + " is not a ReflectionModule");
        }

        AbstractReflectionModule module;
        try {
            Constructor<? extends AbstractReflectionModule> constructor = clazz.getDeclaredConstructor();
            module = constructor.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Class " + clazz.getName() + " new instance failed", e);
        }
        return new ModuleWrapper(module, anno);
    }

    private void reloadModule0(String moduleName, Collection<String> reloadModulePackages, boolean useAnnoPackages) {
        ModuleWrapper moduleWrapper = name2Modules.get(moduleName);
        if (moduleWrapper == null) {
            throw new IllegalArgumentException("moduleName: " + moduleName + " not found");
        }
        reloadModule0(moduleWrapper, reloadModulePackages, useAnnoPackages);
    }

    private void reloadModule0(Class<? extends AbstractReflectionModule> moduleClass, Collection<String> reloadModulePackages, boolean useAnnoPackages) {
        ModuleWrapper moduleWrapper = class2Modules.get(moduleClass);
        if (moduleWrapper == null) {
            throw new IllegalArgumentException("moduleClass: " + moduleClass + " not found");
        }
        reloadModule0(moduleWrapper, reloadModulePackages, useAnnoPackages);
    }

    private void reloadModule0(ModuleWrapper moduleWrapper, Collection<String> reloadModulePackages, boolean useAnnoPackages) {
        if (!useAnnoPackages) {
            if (reloadModulePackages == null || reloadModulePackages.isEmpty()) {
                throw new IllegalArgumentException("reloadModulePackages is empty");
            }
        } else {
            reloadModulePackages = moduleWrapper.getPackages();
        }
        moduleWrapper.setReflections(reloadModulePackages);
        moduleWrapper.reload();
    }


}
